package my.edu.model.bills.sales.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import my.edu.common.constant.MessageConstant;
import my.edu.common.constant.OrderConstant;
import my.edu.common.domain.OrderProductDetail;
import my.edu.common.domain.PageDTO;
import my.edu.common.domain.PageVO;
import my.edu.common.domain.purchase.PriceAndQuantity;
import my.edu.common.exception.BillsException;
import my.edu.common.exception.Order.SalesException;
import my.edu.common.utils.PageUtils;
import my.edu.common.utils.RedisUtils;
import my.edu.constant.BillsType;
import my.edu.constant.DeliveryMethod;
import my.edu.constant.OrderNoConstant;
import my.edu.model.User.service.IUserService;
import my.edu.model.bills.purchase.entity.*;
import my.edu.model.bills.purchase.entity.dto.PurchaseSalesExpensesDTO;
import my.edu.model.bills.purchase.entity.vo.PurchaseReportVO;
import my.edu.model.bills.purchase.entity.vo.PurchaseReturnDetailOrderVO;
import my.edu.model.bills.purchase.entity.vo.PurchaseReturnOrderVO;
import my.edu.model.bills.purchase.service.IPurchaseSalesExpensesService;
import my.edu.model.bills.sales.entity.SalesOrderDetail;
import my.edu.model.bills.sales.entity.SalesReturnOrder;
import my.edu.model.bills.sales.entity.SalesReturnOrderDetail;
import my.edu.model.bills.sales.entity.dto.*;
import my.edu.model.bills.sales.entity.vo.SalesDetailVO;
import my.edu.model.bills.sales.entity.vo.SalesReportVO;
import my.edu.model.bills.sales.entity.vo.SalesVO;
import my.edu.model.commodity.service.IProductService;
import my.edu.model.information.entity.CustomerReceivableBalanceDetail;
import my.edu.model.information.service.IAccountService;
import my.edu.model.information.service.ICustomerService;
import my.edu.utils.ChildrenLoader;
import my.edu.utils.OrderNoUtil;
import my.edu.utils.OrderServiceUtil;
import my.edu.utils.TimeUtil;
import my.edu.websocket.BillWebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import my.edu.model.bills.sales.entity.SalesOrder;
import my.edu.model.bills.sales.mapper.SalesOrderMapper;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOrder> implements ISalesOrderService {

    @Autowired
    private OrderServiceUtil orderServiceUtil;

    private record SalesDTOChecker(
            List<SalesDetailDTO> salesDetailDTOList,
            List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList,
            PriceAndQuantity priceAndQuantity) {
    }

    @Autowired
    private ISalesOrderDetailService salesOrderDetailService;
    @Autowired
    private IPurchaseSalesExpensesService purchaseSalesExpensesService;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private IAccountService accountService;
    @Autowired
    private DeliveryMethod deliveryMethod;
    @Autowired
    private IProductService productService;
    @Autowired
    private OrderNoConstant orderNoConstant;

    @Autowired
    private IUserService userService;

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private ISalesReturnOrderDetailService salesReturnOrderDetailService;
    @Autowired
    private BillWebSocket billWebSocket;

    @Override
    @Transactional
    public void saveNew(SalesDTO salesDTO, String status) {
        //检查dto，账户，人员，商品等等存在性
        SalesDTOChecker checker = checkDTO(salesDTO, status);
        SalesOrder salesOrder = getSalesOrder(BeanUtil.copyProperties(salesDTO, SalesOrder.class, "id", "salesDetailDTOList", "salesExpensesDTOList"), checker, true);
        save(salesOrder);
        salesOrderDetailService.saveBatchByDTO(checker.salesDetailDTOList, salesOrder.getId());
        if (checker.purchaseSalesExpensesDTOList() != null)
            purchaseSalesExpensesService.saveBatchByDTO(BillsType.SALES, checker.purchaseSalesExpensesDTOList(), salesOrder.getId(), salesOrder.getCustomerId(), salesOrder.getCustomerName());
        //更新客户的欠款
        if (!salesOrder.getCollectionStatus().equals(OrderConstant.GET_PAYMENT))
            customerService.addReceivableBalanceDetails(getReceivableBalance(salesOrder));
        billWebSocket.sendToAllClient(BillsType.SALES, "单据类型：销售单;单据编号：" + salesOrder.getOrderNo() + ";提交人：" + salesOrder.getCreatedName());

    }

    @Override
    @Transactional
    public void removeOrder(List<Long> ids) {
        List<SalesOrder> salesOrders = listByIds(ids);
        for (SalesOrder salesOrder : salesOrders) {
            if (salesOrder.getIsAudited() != null && salesOrder.getIsAudited() == 1)
                throw new BillsException(salesOrder.getOrderNo() + MessageConstant
                        .ISAUDIT_CAN_NOT_DEL);
        }
        removeBatchByIds(salesOrders);
        salesOrderDetailService.remove(Wrappers.<SalesOrderDetail>lambdaQuery().in(SalesOrderDetail::getSalesOrderId, ids));
        purchaseSalesExpensesService.removeByOrderTypeAndId(BillsType.PURCHASE, ids);
        //更新客户的欠款
        List<CustomerReceivableBalanceDetail> list = salesOrders.stream().map(this::getReceivableBalance).toList();
        customerService.subReceivableBalanceDetails(list);
    }

    @Override
    public List<SalesVO> listOnly(SalesOrderSearchDTO salesOrderSearchDTO) {
        return list(Wrappers.<SalesOrder>lambdaQuery()
                .like(salesOrderSearchDTO.getOrderNo() != null && !salesOrderSearchDTO.getOrderNo().isEmpty(),
                        SalesOrder::getOrderNo, salesOrderSearchDTO.getOrderNo())
                .between(salesOrderSearchDTO.getBeginTime() != null,
                        SalesOrder::getOrderDate, salesOrderSearchDTO.getBeginTime(), salesOrderSearchDTO.getEndTime())
                .eq(salesOrderSearchDTO.getPaymentStatus() != null && !salesOrderSearchDTO.getPaymentStatus().isEmpty(),
                        SalesOrder::getCollectionStatus, salesOrderSearchDTO.getPaymentStatus())
                .eq(salesOrderSearchDTO.getIsAudited() != null,
                        SalesOrder::getIsAudited, salesOrderSearchDTO.getIsAudited())
                .eq(salesOrderSearchDTO.getSalespersonId() != null,
                        SalesOrder::getSalespersonId, salesOrderSearchDTO.getSalespersonId())
                .eq(salesOrderSearchDTO.getAuditorId() != null,
                        SalesOrder::getAuditorId, salesOrderSearchDTO.getAuditorId())
                .eq(salesOrderSearchDTO.getCustomerId() != null,
                        SalesOrder::getCustomerId, salesOrderSearchDTO.getCustomerId())
                .orderByDesc(SalesOrder::getCreateTime)).stream().map(i -> BeanUtil.copyProperties(i, SalesVO.class)).toList();
    }


    //退款的时候进行检查
    @Override
    public Map<String, Object> checkSalesOrderAndSetCache(SalesReturnDTO salesReturnDTO) {
        //检查存在性和审核状态
        Long salesOrderId = salesReturnDTO.getSalesOrderId();
        SalesOrder byId = getById(salesOrderId);
        if (byId == null || byId.getIsAudited() == 0) throw new BillsException(MessageConstant.ORDER_NOT_EXIST);
        if (byId.getSalesReturnOrderId() != null && byId.getSalesReturnOrderId() != 0 && !byId.getSalesReturnOrderId().equals(salesReturnDTO.getId()))
            throw new BillsException(MessageConstant.HAHRETURNED);
        //获取原订单信息
        Integer quantity = byId.getQuantity();
        String orderNo = byId.getOrderNo();
        int reQuantity = 0;
        //检查退款数量
        List<SalesOrderDetail> list = salesOrderDetailService.list(Wrappers.<SalesOrderDetail>lambdaQuery().eq(SalesOrderDetail::getSalesOrderId, salesOrderId));
        for (SalesReturnDetailDTO returnDetailDTO : salesReturnDTO.getSalesReturnDetailDTOList()) {
            Long productId = returnDetailDTO.getProductId();
            SalesOrderDetail salesOrderDetail = list.stream().filter(i -> i.getProductId().equals(productId)).findFirst().orElse(null);
            if (salesOrderDetail == null) throw new BillsException(MessageConstant.PRODUCT_NOT_FOUND);
            Integer tempQ = returnDetailDTO.getQuantity();
            if (returnDetailDTO.getQuantity() > salesOrderDetail.getQuantity())
                throw new BillsException(MessageConstant.OVERMAX_SOURCEQUANTITY);
            reQuantity += tempQ;
        }
        //设置退款状态
        String returnStatus = reQuantity < quantity ? OrderConstant.PART_RETURN : OrderConstant.GET_RETURN;
        return Map.of("quantity", quantity, "orderNo", orderNo, "returnStatus", returnStatus);
    }

    @Override
    public void updateReturnId(SalesReturnOrder salesReturnOrder, String returnStatus) {
        lambdaUpdate()
                .set(SalesOrder::getSalesReturnOrderNo, salesReturnOrder.getOrderNo())
                .set(SalesOrder::getSalesReturnOrderId, salesReturnOrder.getId())
                .set(SalesOrder::getRefundStatus, returnStatus)
                .eq(SalesOrder::getId, salesReturnOrder.getSalesOrderId())
                .update();
    }

    @Override
    public void updateReturnId(Long id, SalesReturnOrder salesReturnOrder,String returnStatus) {
        if (!id.equals(salesReturnOrder.getSalesOrderId())) {
            lambdaUpdate()
                    .set(SalesOrder::getSalesReturnOrderNo, null)
                    .set(SalesOrder::getSalesReturnOrderId, null)
                    .set(SalesOrder::getRefundStatus, OrderConstant.NOT_RETURN)
                    .eq(SalesOrder::getId, id)
                    .update();
        }
        if (salesReturnOrder.getSalesOrderId() !=null && salesReturnOrder.getSalesOrderId() != 0 ) {
            lambdaUpdate()
                    .set(SalesOrder::getSalesReturnOrderNo, salesReturnOrder.getOrderNo())
                    .set(SalesOrder::getSalesReturnOrderId, salesReturnOrder.getId())
                    .set(SalesOrder::getRefundStatus, returnStatus)
                    .eq(SalesOrder::getId, salesReturnOrder.getSalesOrderId())
                    .update();
        }
    }

    @Override
    @Transactional
    public void removeReturn(List<Long> ids) {
        List<SalesOrder> list = lambdaQuery().in(SalesOrder::getSalesReturnOrderId, ids).list();
        list.forEach(i -> {
            i.setSalesReturnOrderNo(" ");
            i.setSalesReturnOrderId(0L);
            i.setRefundStatus(OrderConstant.NOT_RETURN);
        });
        updateBatchById(list);
    }

    @Override
    public BigDecimal getTodaySale() {
        List<SalesOrder> list = lambdaQuery()
                .between(SalesOrder::getCreateTime, TimeUtil.getTodayStartTime(), TimeUtil.getTodayEndTime())
                .list();
        return getReceivedAmountTotalInOrder(list);
    }

    @Override
    public BigDecimal getMonthSale() {
        // 假设你有一个方法可以根据日期范围查询采购金额
        List<SalesOrder> list = lambdaQuery()
                .between(SalesOrder::getCreateTime, TimeUtil.getStartOfMonth(), TimeUtil.getEndOfMonth())
                .list();

        return getReceivedAmountTotalInOrder(list);
    }

    @Override
    public BigDecimal getYesterdaySale() {
        // 获取昨天的日期
        LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
        List<SalesOrder> list = lambdaQuery()
                .between(SalesOrder::getCreateTime, TimeUtil.getDayStartTime(yesterday), TimeUtil.getDayEndTime(yesterday))
                .list();
        return getReceivedAmountTotalInOrder(list);
    }

    @Override
    public BigDecimal getYearSale() {
        // 假设你有一个方法可以根据日期范围查询采购金额
        List<SalesOrder> list = lambdaQuery()
                .between(SalesOrder::getCreateTime, TimeUtil.getStartOfYear(), TimeUtil.getTodayEndTime())
                .list();
        return getReceivedAmountTotalInOrder(list);
    }

    @Override
    public Map<YearMonth, BigDecimal> getSalePriceList() {
        LinkedHashMap<YearMonth, BigDecimal> map = new LinkedHashMap<>();
        LocalDate today = LocalDate.now();
        YearMonth currentYearMonth = YearMonth.from(today);
        LocalDateTime dateStart = currentYearMonth.atDay(1).atTime(LocalTime.MIN);
        LocalDateTime dateEnd = currentYearMonth.atEndOfMonth().atTime(LocalTime.MAX);
        List<SalesOrder> list = lambdaQuery().between(SalesOrder::getCreateTime, dateStart, dateEnd).list();
        BigDecimal totalInOrder = getReceivedAmountTotalInOrder(list);
        map.put(currentYearMonth, totalInOrder);

        for (int i = 1; i <= 6; i++) {
            currentYearMonth = currentYearMonth.minusMonths(1);
            dateStart = currentYearMonth.atDay(1).atTime(LocalTime.MIN);
            dateEnd = currentYearMonth.atEndOfMonth().atTime(LocalTime.MAX);
            List<SalesOrder> l = lambdaQuery().between(SalesOrder::getCreateTime, dateStart, dateEnd).list();
            BigDecimal totalInOrder2 = getReceivedAmountTotalInOrder(l);
            map.put(currentYearMonth, totalInOrder2);
        }

        return orderServiceUtil.reverseMap(map);
    }

    @Override
    public JSONObject getReportList(PageDTO pageDTO, SalesOrderSearchDTO salesOrderSearchDTO) {
        //查询采购与退货的详情
        List<SalesOrderDetail> reportList = salesOrderDetailService.getReportList(salesOrderSearchDTO);
        List<SalesReturnOrderDetail> returnReportList = salesReturnOrderDetailService.getReportList(salesOrderSearchDTO);

        Map<Long, SalesReportVO> map = new HashMap<>();
        BigDecimal realityPriceTotal = BigDecimal.ZERO;
        for (SalesOrderDetail record : reportList) {
            if (record.getProductName() == null) System.out.println("名字为空456654" + record.getSalesOrderId());
            SalesReportVO salesReportVO = map.computeIfAbsent(record.getProductId(), i -> {
                SalesReportVO vo = BeanUtil.copyProperties(record, SalesReportVO.class);
                vo.setInSum(0L);
                vo.setOutSum(0L);
                vo.setOutSumPrice(BigDecimal.ZERO);
                vo.setInSumPrice(BigDecimal.ZERO);
                vo.setInOutSumPrice(BigDecimal.ZERO);
                return vo;
            });
            Integer quantity = record.getQuantity();
            BigDecimal multiply = record.getCurrentPrice().multiply(BigDecimal.valueOf(quantity));
            salesReportVO.setInSum(quantity + salesReportVO.getInSum());
            salesReportVO.setInSumPrice(multiply.add(salesReportVO.getInSumPrice()));
            realityPriceTotal = realityPriceTotal.add(multiply);
        }

        for (SalesReturnOrderDetail record : returnReportList) {
            if (record.getProductName() == null) System.out.println("名字为空" + record.getSalesReturnOrderId());
            SalesReportVO salesReportVO = map.computeIfAbsent(record.getProductId(), i -> {
                SalesReportVO vo = BeanUtil.copyProperties(record, SalesReportVO.class);
                vo.setInSum(0L);
                vo.setOutSum(0L);
                vo.setOutSumPrice(BigDecimal.ZERO);
                vo.setInSumPrice(BigDecimal.ZERO);
                vo.setInOutSumPrice(BigDecimal.ZERO);
                return vo;
            });
            Integer quantity = record.getQuantity();
            BigDecimal multiply = record.getCurrentPrice().multiply(BigDecimal.valueOf(quantity));
            salesReportVO.setOutSum(quantity + salesReportVO.getOutSum());
            salesReportVO.setOutSumPrice(multiply.add(salesReportVO.getOutSumPrice()));
            realityPriceTotal = realityPriceTotal.subtract(multiply);
        }

        List<SalesReportVO> list = map.values().stream()
                .peek(i -> i.setInOutSumPrice(i.getInSumPrice().subtract(i.getOutSumPrice())))
                .toList();

        return new JSONObject()
                .putOnce("realityPriceTotal", realityPriceTotal)
                .putOnce("data", list);
    }

    private BigDecimal getReceivedAmountTotalInOrder(List<SalesOrder> list) {
        return list.stream().map(SalesOrder::getReceivedAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
    }


    @Override
    public void updateOrder(SalesDTO salesDTO, String status) {
        //存在性和有无审核校验
        SalesOrder salesOrderById = getById(salesDTO.getId());
        if (salesOrderById == null) throw new BillsException(MessageConstant.ORDER_NOT_EXIST);
        if (salesOrderById.getIsAudited() != null && salesOrderById.getIsAudited() == 1)
            throw new BillsException(MessageConstant.ISAUDIT_CAN_NOT_UPDATE);
        if (salesOrderById.getSalesReturnOrderId() != null && salesOrderById.getSalesReturnOrderId() > 0)
            throw new BillsException(MessageConstant.ISRETURN_CAN_NOT_UPDATE);

        SalesDTOChecker checker = checkDTO(salesDTO, status);
        BeanUtil.copyProperties(salesDTO, salesOrderById, "id", "salesDetailDTOList", "salesExpensesDTOList");
        getSalesOrder(salesOrderById, checker, false);
        updateById(salesOrderById);
        salesOrderDetailService.updateBatchByDTO(checker.salesDetailDTOList, salesOrderById.getId());
        purchaseSalesExpensesService.updateBatchByDTO(salesOrderById.getId(), BillsType.SALES, checker.purchaseSalesExpensesDTOList(), salesOrderById.getId(), salesOrderById.getCustomerId(), salesOrderById.getCustomerName());
        //更新客户的欠款
        customerService.updateReceivableBalanceDetails(getReceivableBalance(salesOrderById));
        billWebSocket.sendToAllClient(BillsType.SALES, "更新;单据类型：销售单;单据编号：" + salesOrderById.getOrderNo() + ";提交人：" + salesOrderById.getUpdateName());

    }

    @Override
    public void auditOrder(List<Long> ids) {
        //检查是否已经审核
        List<SalesOrder> salesOrders = listByIds(ids);
        if (salesOrders.isEmpty()) throw new BillsException(MessageConstant.ORDER_NOT_EXIST);
        for (SalesOrder salesOrder : salesOrders) {
            if (salesOrder.getIsAudited() != null && salesOrder.getIsAudited() == 1)
                throw new BillsException(salesOrder.getOrderNo() + MessageConstant.ISAUDITED);
        }
        orderServiceUtil.setAuditStatus(this, ids, true);
        //更新库存
        List<Long> salesIdlist = salesOrders.stream().map(SalesOrder::getId).toList();
        List<OrderProductDetail> orderProductDetails = salesOrderDetailService
                .list(Wrappers.<SalesOrderDetail>lambdaQuery()
                        .in(SalesOrderDetail::getSalesOrderId, salesIdlist))
                .stream().map(i -> (OrderProductDetail) i).toList();
        productService.subCurrentStock(orderProductDetails);
        Map<Long, BigDecimal> accountIdToTotalAmountMap = orderServiceUtil.getAccountIdToTotalAmountMap(salesOrders);
        accountService.addBalance(accountIdToTotalAmountMap);
    }

    @Override
    public void rauditOrder(List<Long> ids) {
        List<SalesOrder> salesOrders = listByIds(ids);
        if (salesOrders.isEmpty()) throw new BillsException(MessageConstant.ORDER_NOT_EXIST);
        for (SalesOrder salesOrder : salesOrders) {
            if (salesOrder.getIsAudited() == null || salesOrder.getIsAudited() == 0)
                throw new BillsException(salesOrder.getOrderNo() + MessageConstant.NOTAUDITED);
            if (salesOrder.getSalesReturnOrderId() != null && salesOrder.getSalesReturnOrderId() != 0)
                throw new BillsException(MessageConstant.ISRETURN_CAN_NOT_AUDIT + "，编号:" + salesOrder.getOrderNo());
        }
        orderServiceUtil.setAuditStatus(this, ids, false);
        //更新库存
        List<OrderProductDetail> orderProductDetails = salesOrderDetailService
                .list(Wrappers.<SalesOrderDetail>lambdaQuery()
                        .in(SalesOrderDetail::getSalesOrderId, ids))
                .stream().map(i -> (OrderProductDetail) i).toList();
        productService.addCurrentStock(orderProductDetails);
        Map<Long, BigDecimal> accountIdToTotalAmountMap = orderServiceUtil.getAccountIdToTotalAmountMap(salesOrders);
        accountService.subBalance(accountIdToTotalAmountMap);
    }

    @Override
    public Object getOrderOne(Long id) {
        MPJLambdaWrapper<SalesOrder> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAsClass(SalesOrder.class, SalesVO.class)
                .selectCollection(SalesOrderDetail.class, SalesVO::getSalesDetailDTOList)
                .leftJoin(SalesOrderDetail.class, SalesOrderDetail::getSalesOrderId, SalesOrder::getId)
                .eq(SalesOrder::getId, id);
        return baseMapper.selectJoinOne(SalesVO.class, wrapper);
    }

    @Override
    public PageVO<SalesVO> getSalesOrderList(PageDTO page, SalesOrderSearchDTO salesOrderSearchDTO) {
        Page<SalesVO> objectPage = new Page<>(page.getPage(), page.getSize());
        MPJLambdaWrapper<SalesOrder> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAsClass(SalesOrder.class, SalesVO.class)
                .like(salesOrderSearchDTO.getOrderNo() != null && !salesOrderSearchDTO.getOrderNo().isEmpty(),
                        SalesOrder::getOrderNo, salesOrderSearchDTO.getOrderNo())
                .between(salesOrderSearchDTO.getBeginTime() != null,
                        SalesOrder::getOrderDate, salesOrderSearchDTO.getBeginTime(), salesOrderSearchDTO.getEndTime())
                .eq(salesOrderSearchDTO.getDeliveryMethod() != null,
                        SalesOrder::getDeliveryMethod, salesOrderSearchDTO.getDeliveryMethod())
                .eq(salesOrderSearchDTO.getPaymentStatus() != null && !salesOrderSearchDTO.getPaymentStatus().isEmpty(),
                        SalesOrder::getCollectionStatus, salesOrderSearchDTO.getPaymentStatus())
                .eq(salesOrderSearchDTO.getPaymentTerms() != null && !salesOrderSearchDTO.getPaymentTerms().isEmpty(),
                        SalesOrder::getPaymentTerms, salesOrderSearchDTO.getPaymentTerms())
                .eq(salesOrderSearchDTO.getReturnStatus() != null && !salesOrderSearchDTO.getReturnStatus().isEmpty(),
                        SalesOrder::getRefundStatus, salesOrderSearchDTO.getReturnStatus())
                .eq(salesOrderSearchDTO.getIsAudited() != null,
                        SalesOrder::getIsAudited, salesOrderSearchDTO.getIsAudited())
                .eq(salesOrderSearchDTO.getSalespersonId() != null,
                        SalesOrder::getSalespersonId, salesOrderSearchDTO.getSalespersonId())
                .eq(salesOrderSearchDTO.getSalesReturnOrderId() != null,
                        SalesOrder::getSalesReturnOrderId, salesOrderSearchDTO.getSalesReturnOrderId())
                .eq(salesOrderSearchDTO.getAuditorId() != null,
                        SalesOrder::getAuditorId, salesOrderSearchDTO.getAuditorId())
                .eq(salesOrderSearchDTO.getCustomerId() != null,
                        SalesOrder::getCustomerId, salesOrderSearchDTO.getCustomerId())
                .orderByDesc(SalesOrder::getCreateTime);
        Page<SalesVO> salesOrderPage = baseMapper.selectJoinPage(objectPage, SalesVO.class, wrapper);
//        List<CompletableFuture<Void>> futures = new ArrayList<>();
//        for (SalesVO vo : salesOrderPage.getRecords()) {
//            futures.add(CompletableFuture.runAsync(() -> setVoDetail(vo)));
//        }
//        // 等待所有异步任务完成
//        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        if (CollUtil.isNotEmpty(salesOrderPage.getRecords())) {
            ChildrenLoader.loadAndFillDTO(
                    salesOrderPage.getRecords(),
                    SalesVO::getId,
                    ids -> salesOrderDetailService.list(
                            Wrappers.<SalesOrderDetail>lambdaQuery().in(SalesOrderDetail::getSalesOrderId, ids)),
                    SalesDetailVO::getSalesOrderId,
                    SalesDetailVO.class,
                    SalesVO::setSalesDetailDTOList);
        };

        return PageUtils.toPage(salesOrderPage);
    }

//    @Async
//    protected void setVoDetail(SalesVO vo) {
//        vo.setSalesDetailDTOList(
//                BeanUtil.copyToList(
//                        salesOrderDetailService.list(Wrappers.<SalesOrderDetail>lambdaQuery().eq(SalesOrderDetail::getSalesOrderId, vo.getId()))
//                        , SalesDetailVO.class
//                )
//        );
//    }

    @Override
    public SalesVO getSalesOrderOne(Long id) {
        MPJLambdaWrapper<SalesOrder> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAsClass(SalesOrder.class, SalesVO.class)
                .selectCollection(SalesOrderDetail.class, SalesVO::getSalesDetailDTOList)
                .selectCollection(PurchaseSalesExpenses.class, SalesVO::getSalesExpensesDTOList)
                .leftJoin(SalesOrderDetail.class, SalesOrderDetail::getSalesOrderId, SalesOrder::getId)
                .leftJoin(PurchaseSalesExpenses.class, on -> on
                        .eq(PurchaseSalesExpenses::getSourceDocumentId, SalesOrder::getId)
                        .eq(PurchaseSalesExpenses::getBillsType, BillsType.SALES))
                .eq(SalesOrder::getId, id);
        SalesVO salesOrderVO = baseMapper.selectJoinOne(SalesVO.class, wrapper);
        return salesOrderVO;
    }


    private CustomerReceivableBalanceDetail getReceivableBalance(SalesOrder salesOrder) {
        String collectionStatus = salesOrder.getCollectionStatus();
        Long customerId = salesOrder.getCustomerId();
        BigDecimal totalPrice;
        switch (collectionStatus) {
            case OrderConstant.NOT_PAYMENT -> {
                totalPrice = salesOrder.getAmountAfterDiscount();
            }
            case OrderConstant.PART_PAYMENT -> {
                totalPrice = salesOrder.getAmountAfterDiscount().subtract(salesOrder.getReceivedAmount());
            }
            case OrderConstant.GET_PAYMENT -> {
                totalPrice = BigDecimal.ZERO;
            }
            default -> throw new RuntimeException(MessageConstant.CAN_NOT_FOUND_PAYSTATUS);
        }
        return CustomerReceivableBalanceDetail.builder()
                .billsType(BillsType.SALES)
                .bill_id(salesOrder.getId())
                .customer_id(customerId)
                .receivable_balance(totalPrice)
                .billNo(salesOrder.getOrderNo())
                .build();
    }

    private SalesOrder getSalesOrder(SalesOrder salesOrder, SalesDTOChecker checker, boolean isNew) {
        PriceAndQuantity priceAndQuantity = checker.priceAndQuantity();
        //设置其他字段然后新增
        salesOrder.setQuantity(priceAndQuantity.getQuantity());//总数量
        salesOrder.setSalesAmount(priceAndQuantity.getAmount());//销售金额
        if (salesOrder.getOrderNo() == null || salesOrder.getOrderNo().isEmpty()) {
            //设置No
            String orderNo = OrderNoUtil.generateOrderNo(orderNoConstant.getSalesNo());
            salesOrder.setOrderNo(orderNo);
        } else {
            //检查是否有重复no
            long count = count(Wrappers.<SalesOrder>lambdaQuery().eq(SalesOrder::getOrderNo, salesOrder.getOrderNo()));
            if (isNew && count > 0) throw new BillsException(MessageConstant.ORDER_NO_EXISTS);
        }

        //设置优惠后金额
        BigDecimal amount = salesOrder.getSalesAmount().subtract(salesOrder.getDiscountAmount());
        if (amount.compareTo(BigDecimal.ZERO) < 0) {
            throw new SalesException(MessageConstant.AMOUNT_ERROR);
        }
        salesOrder.setAmountAfterDiscount(amount);//优惠后金额
        //设置欠款
        BigDecimal debt = amount.subtract(salesOrder.getReceivedAmount());
        salesOrder.setDebt(debt);
        //设置付款状态
        setPaidStatusAndDebt(salesOrder);
        if (salesOrder.getCollectionStatus().equals(OrderConstant.GET_PAYMENT))
            salesOrder.setCollectionArrivalDate(LocalDate.now());
        //设置退款状态
        salesOrder.setRefundStatus(OrderConstant.NOT_RETURN);
        if (isNew) salesOrder.setVersion(0);
        salesOrder.setIsAudited(0);
        return salesOrder;
    }

    private void setPaidStatusAndDebt(SalesOrder salesOrder) {
        BigDecimal amountAfterDiscount = salesOrder.getAmountAfterDiscount();
        BigDecimal paidAmount = salesOrder.getReceivedAmount();
        if (amountAfterDiscount.compareTo(BigDecimal.ZERO) != 0 && amountAfterDiscount.compareTo(paidAmount) != 0) {
            //没有付一分钱
            if (paidAmount.compareTo(BigDecimal.ZERO) == 0)
                salesOrder.setCollectionStatus(OrderConstant.NOT_PAYMENT);
            else if (amountAfterDiscount.compareTo(paidAmount) > 0)
                salesOrder.setCollectionStatus(OrderConstant.PART_PAYMENT);
            else throw new BillsException(MessageConstant.PAID_AMOUNT_ERROR);
        } else {
            salesOrder.setCollectionStatus(OrderConstant.GET_PAYMENT);

        }

    }

    private SalesDTOChecker checkDTO(SalesDTO salesDTO, String status) {
        List<SalesDetailDTO> salesDetailDTOList = salesDTO.getSalesDetailDTOList();
        List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList = salesDTO.getSalesExpensesDTOList();
        orderServiceUtil.checkDTO(salesDTO.getDeliveryMethod(), salesDTO.getSettlementAccountId(), salesDTO.getSalespersonId(), null, salesDTO.getCustomerId());
        //校验detail，并返回商品总价和数量
        PriceAndQuantity priceAndQuantity = orderServiceUtil.checkAndGetProductDetail(status, salesDetailDTOList);
        return new SalesDTOChecker(salesDetailDTOList, purchaseSalesExpensesDTOList, priceAndQuantity);
    }
}